package com.tcxhb.job.core.schedule;

import com.tcxhb.job.dao.dataobject.JobInfoDO;
import com.tcxhb.job.core.entity.JobRunDTO;
import com.tcxhb.job.core.schedule.execute.JobRunExecutor;
import com.tcxhb.job.core.service.job.JobInfoService;
import com.tcxhb.job.common.Thread.NamedThreadFactory;
import com.tcxhb.job.core.utils.SchedulerTimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @Description:
 * @Auther: tcxhb
 * @Date: 2023/11/4
 */
@Slf4j
@Component
public class JobScanScheduler extends BaseScheduler implements Scheduler {

    @Autowired
    private JobInfoService jobInfoService;
    @Autowired
    private JobWaitScheduler waitScheduler;
    @Autowired
    private JobRunExecutor jobRunExecutor;

    private ScheduledExecutorService jobScanSchedule = Executors.newScheduledThreadPool(1,
            new NamedThreadFactory("job-scan", true));
    //
    private static Integer pageSize = 5000;
    private static Long preReadTime = 10000L;//10秒
    // 间隔时间5秒拉取一次任务
    private Integer periodTime = 10;

    @PostConstruct
    @Override
    public void start() {
        jobScanSchedule.scheduleAtFixedRate(() -> {
            try {
                if (isRunningServer()) {
                    Long start = System.currentTimeMillis();
                    log.info("job-scan-start");
                    scan();
                    Long end = System.currentTimeMillis();
                    log.info("job-scan-cost:" + (end - start) / 1000);
                } else {
                    log.info("server-not-run");
                }
            } catch (Exception e) {
                log.info("job-scan-error:", e);
            }
        }, 10, periodTime, TimeUnit.SECONDS);
    }

    //扫描任务列表
    public void scan() {
        Long lastId = 0L;
        Long now = new Date().getTime();
        //每次只有一个线程
        List<JobInfoDO> minJob = jobInfoService.scan(lastId, now + preReadTime, pageSize);
        for (JobInfoDO jobDO : minJob) {
            //当前时间大于调度时间
            if (now >= jobDO.getNextTime()) {
                //需要调度的
                doSchedule(now, jobDO);
            } else if (now < jobDO.getNextTime()) {
                //等待时间片轮询执行
                waitScheduler.submit(jobDO);
            }
        }
    }

    /**
     * @param now
     * @param jobDO
     */
    public void doSchedule(Long now, JobInfoDO jobDO) {
        // 5秒内的立即执行
        if (jobDO.getNextTime() + preReadTime >= now) {
            JobRunDTO jobRun = new JobRunDTO(jobDO.getId(), jobDO.getNextTime());
            jobRunExecutor.run(jobRun);
        }
        //超过10秒的
        else {
            log.error("job-overTime,{},{},{}", jobDO.getId(), now, jobDO.getNextTime());
            Long nextTime = SchedulerTimeUtils.nextSchedulerTime(jobDO, new Date());
            jobInfoService.freshNextScheduleTime(jobDO, nextTime);
        }
    }
}
